﻿
#include <db_cxx.h>
#include <string>
#include <map>

#ifdef _DEBUG
	#pragma comment(lib,"libdb47d.lib")
#else
	#pragma comment(lib,"libdb47.lib")
#endif

namespace BasicPackage
{

	#define MAX_BLOCK_SIZE 1024
	
	class BdbClass
	{
	private:
		//全局静态变量
		static DbEnv *dbenv;

		//内部成员变量
		DbEnv *m_pDbEnv;
		Db *m_pDb;

	public:
		BdbClass(DbEnv * env)
		{
			m_pDbEnv=env;
			m_pDb=new Db(env,0);
		}

		~BdbClass()
		{
			if(m_pDb) 
				m_pDb->close(0);
		}

		void open(const std::string &path,const std::string &dbName,bool isSecondary,u_int32_t cFlags)
		{
			std::string dbFileName_;
			try
			{
				dbFileName_ = path + dbName;

				// Redirect debugging information to std::cerr
				m_pDb->set_error_stream(&std::cerr);

				// If this is a secondary database, support
				// sorted duplicates
				if (isSecondary)
					m_pDb->set_flags(DB_DUPSORT);

				// Open the database
				m_pDb->open(NULL, dbFileName_.c_str(), NULL/*dbName.c_str()*/, DB_BTREE, cFlags, 0);
			}
			// DbException is not a subclass of std::exception, so we
			// need to catch them both.
			catch(DbException &e)
			{
				std::cerr << "Error opening database: " << dbFileName_ << "\n";
				std::cerr << e.what() << std::endl;
			}
			catch(std::exception &e)
			{
				std::cerr << "Error opening database: " << dbFileName_ << "\n";
				std::cerr << e.what() << std::endl;
			}
		}


		bool load(const string& index, int* value)
		{
			try
			{
				Dbt key, data;
				key.set_data((void*)index.c_str());
				key.set_size((u_int32_t)index.length()+1);

				//多线程需要为DBT设置内存分配标志
				data.set_flags(DB_DBT_MALLOC);

				if (m_pDb->get(NULL, &key, &data, 0) != 0) {
					return false;
				}

				(*value)=(*(int *)data.get_data());
			}

			catch(DbException &e) {
				m_pDb->err(e.get_errno(), "Error!");
				//AfxTrace(e.what());
				return false;
			} catch(std::exception &e) {
				m_pDb->errx("Error! %s", e.what());
				//AfxTrace(e.what());
				return false;
			}

			return true;
		}

		//对于基本类型和组合类型
		bool find(string& prefix,std::map<string,int> & m)
		{
			Dbc *cursorp;
			try {
				// Database open omitted
				// Get the cursor
				m_pDb->cursor(NULL, &cursorp, 0);
				// Set up our DBTs
				Dbt data;
				Dbt key;
				// Iterate over the database, deleting each record in turn.
				int ret;
				while ((ret = cursorp->get(&key, &data,
					DB_NEXT)) == 0) {
						std::cout << (char *)key.get_data()  << "\t" << (*(int*) data.get_data()) << std::endl;

						//比较前缀
						if(::strncmp((char *)key.get_data(),prefix.c_str(),prefix.size())==0)
						{
							m.insert(make_pair(string((char *)key.get_data()),(*(int*) data.get_data())));
						}
				}
			} catch(DbException &e) {
				m_pDb->err(e.get_errno(), "Error!");
			} catch(std::exception &e) {
				m_pDb->errx("Error! %s", e.what());
			}
			// Cursors must be closed
			if (cursorp != NULL)
				cursorp->close();

			return true;
		}

		bool dump()
		{
			Dbc *cursorp;
			try {
				// Database open omitted
				// Get the cursor
				m_pDb->cursor(NULL, &cursorp, 0);
				// Set up our DBTs
				Dbt data;
				Dbt key;
				// Iterate over the database, deleting each record in turn.
				int ret;
				while ((ret = cursorp->get(&key, &data,
					DB_NEXT)) == 0) {
						std::cout << (char *)key.get_data()  << "\t" << (*(int*) data.get_data()) << std::endl;
				}
			} catch(DbException &e) {
				m_pDb->err(e.get_errno(), "Error!");
			} catch(std::exception &e) {
				m_pDb->errx("Error! %s", e.what());
			}
			// Cursors must be closed
			if (cursorp != NULL)
				cursorp->close();

			return true;
		}

		bool save(const string& key,int value)
		{

			Dbt _key, _data;

			BinaryOutputStream out;
			int ret = 0;
			try
			{
				_key.set_data((void*)key.c_str());
				_key.set_size((u_int32_t)(key.length()+1));

				_data.set_data((void*)&value);
				_data.set_size(sizeof(value));

				ret = m_pDb->put(NULL, &_key, &_data, 0) ;
			}
			catch(DbException &e) {
				m_pDb->err(e.get_errno(), "Error!");
				//AfxTrace(e.what());
				return false;
			} catch(std::exception &e) {
				m_pDb->errx("Error! %s", e.what());
				//AfxTrace(e.what());
				return false;
			}

			return (ret == 0);
		}

		static DbEnv * GetDBEnv(std::string &dbHome)
		{
			if(dbenv == NULL)
			{
				u_int32_t DBENV_ctor_flag = 0;
				//u_int32_t DBENV_open_flag = DB_CREATE | DB_INIT_MPOOL | DB_PRIVATE | DB_INIT_LOCK|DB_THREAD/*|DB_INIT_LOG*/;
				u_int32_t DBENV_open_flag = DB_CREATE | DB_INIT_MPOOL| DB_PRIVATE|DB_THREAD /*|  DB_INIT_LOCK|DB_INIT_LOG*/;
				try
				{
					dbenv = new DbEnv(/*DB_CXX_NO_EXCEPTIONS*/DBENV_ctor_flag);
					dbenv->set_error_stream(&cerr);

					dbenv->open(dbHome.c_str() ,DBENV_open_flag,0644);
					//dbenv->set_flags(DB_AUTO_COMMIT,1);
				}
				catch(DbException &ex)
				{
					std::cout << ex.what() << std::endl;
				}
				catch (exception& e) 
				{
					std::cout << e.what() << std::endl;
				}
				catch (...) 
				{
					std::cout << "数据库环境初始化失败,程序即将关闭." << std::endl;
				}
			}
			return dbenv;
		}

		static void ReleaseDBEnv()
		{
			if(dbenv != NULL)
			{
				dbenv->close(0);
				delete dbenv;
				dbenv = NULL;
			}
		}

	};


	DbEnv *BdbClass::dbenv=NULL;

};
